# coding:utf8

import json
import os
from types import ModuleType

from log import logger


class Json:
    def __init__(self, path):
        logger.debug("in Json Class of `__init__` function")
        if not os.path.exists(path):
            # 如果文件不存在,则创建一个文件
            logger.debug("path: {} is not exists!, will create it.".format(path))
            with open(path, encoding='utf8', mode='w+') as f:
                pass
        self.path = path
    
    def load(self):
        """
        从json文件中读取对象
        """
        with open(self.path, mode='r', encoding='utf8') as f:
            return json.load(f)

    def dump(self, dictObj):
        """
        把一个对象下载到文件
        这个对象必须是以下类型之一:
        字典, 列表,元组, int, float, str类型
        """
        with open(self.path, encoding='utf8', mode='w') as f:
            json.dump(dictObj, f, ensure_ascii=False, indent=4)
    
        
        
class JsonA(Json):
    """
    保存的方式:
    默认数据从哪里来 1 无源,自定义一个字典定义默认数据 2 从类中  3 从类对象中 4 从模块中
    第一种 对应的是字典变量
    第二种对象的是类的属性
    第三种对应的是类的对象的属性
    第四种对应的是模块的属性
    就是看你把数据存在哪里了
    
    
    **************** json文件的结构 ***************
    每个JsonA类或者子类的对象,都对应着json文件里的一个mainkey和一个数据的字典
    json文件:
    key1 -> dict1   # JsonHandleModule 对象1
    key2 -> dict2   # JsonHandleModule 对象2
    key3 -> dict3   # JsonHandleObject 对象1
    
    """

    def __init__(self, jsonpath: str, mainKey: str, default_dit=None):
        """
        因为mainKey在初始化的时候要用到,所以必须在初始化时给到;
        且mainKey不需要再更改,所以不需要property函数;
        
        文件不存 - > 初始化的时候创建
        文件存在, 没有key ->
        文件存在, 有key -> 直接读取;
        """
        self.default_dict = default_dit
        self.mainKey = mainKey
        self.path = jsonpath
        # super(JsonA, self).__init__(jsonpath)
        self.load()

    def getDict(self):
        """
        self.dict 是数据操作的出口
        """
        return self.dict

    def load(self):
        """
        从本地配置文件里面加载dict
        """
        if not os.path.exists(self.path):
            with open(self.path, mode='w+', encoding='utf8') as f:
                if self.default_dict is not None:
                    dict_combin = {self.mainKey: self.default_dict}
                    tsr = json.dumps(dict_combin, indent=4, ensure_ascii=False)
                    logger.info("config file {} is not exists, write to data: {}".format(self.path, tsr))
                    f.write(tsr)
                    self.dict = self.default_dict
        else:
            _dict:dict = super(JsonA, self).load()
            # 如果不存在mainkey就创建一个key,并设定其值为默认值;
            self.dict = _dict.setdefault(self.mainKey, self.default_dict)
        return self.dict

    def dump(self):
        """
        需要先load总的dict,然后把本类的dict加上key,配置进去
        """

        _fill_dict = super(JsonA, self).load()
        _fill_dict[self.mainKey] = self.dict
        super(JsonA, self).dump(_fill_dict)




class JsonHandleModule(JsonA):
    """
    如果一个配置文件不存在,那我们就创建它,如果它存在,那么就要先读取出来;
    加入一个key,value就是我们要保存的配置;
    """
    
    def __init__(self, jsonpath, mainKey,  module: ModuleType):
        
        # 获取要配置的模块的字典
        self.module = module
        self.default_dict = self.get_config(module)
        
        super(JsonHandleModule, self).__init__(jsonpath, mainKey, default_dit=self.default_dict)
    
    def load(self):
        super(JsonHandleModule, self).load()
        for attr in self.dict:
            value = self.dict.get(attr)
            setattr(self.module, attr, value)
        
    
    def dump(self):
        self.dict = self.get_config(self.module)
        super(JsonHandleModule, self).dump()
    
    @staticmethod
    def get_config(module: ModuleType):
        """
        获取一个模块里面所有大写属性的字典
        {大写属性字符串 : 属性的值}
        """
        moduleUpperAttrDict = {}
        # dir(dt) -> list
        for keyname in dir(module):
            if keyname.isupper():
                moduleUpperAttrDict.setdefault(keyname, getattr(module, keyname))
        return moduleUpperAttrDict
 
class Config:
    def __init__(self):
        self.a1 = ""
        self.b1 = ""
        pass
    


class JsonB(Json):
    def __init__(self, path):
        super(JsonB, self).__init__(path)
        self.allDict = {}
        
        pass
    
    def load(self):
        try:
            self.allDict =  super(JsonB, self).load()
        except:
            self.allDict = {}
            return self.allDict
        
        if self.allDict in (None, "", []):
            self.allDict = {}
        
        return self.allDict
    
    
    def dump(self, cell_obj=None):
        if isinstance(cell_obj, (tuple, list)):
            key_ = cell_obj[0]
            value = cell_obj[1]
            self.allDict.update({key_: value})
            
        super(JsonB, self).dump(self.allDict)
        
        
        
        
    
    
class JsonHandleObject(JsonB):
    """
    处理一些对象
    """

    def __init__(self, path):
        super(JsonHandleObject, self).__init__(path)

    def dump(self, obj=None):
        obj_dict = obj.__dict__
        key = obj.__class__.__name__
        
        super(JsonHandleObject, self).dump((key, obj_dict))

    def load(self, cls:type):
        """
        load里面包含dump,如果在allDict里面没有找到对应的key就会dump一个默认的;
        :return
            cls 对应的object
        """
        super(JsonHandleObject, self).load()
        
        # 如果key是一个类名
        if type(cls) != type:
            return None
        
        key_class = cls.__name__
        rev_dict =  self.allDict.get(key_class, None)
        
        cls_obj = cls()

        # 如果没有对应的key,则要新建一个默认的,并保存
        if rev_dict is None:
            self.dump(cls_obj)
            return cls_obj
        
        # rev is dict
        cls_obj.__dict__.update(rev_dict)
        return cls_obj
        
        
        
        
    

